home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-14 | 9.6 KB | 359 lines | [TEXT/MMCC] |
- //--------------------------------
- //--------------------------------
- //
- // Code to strip the cluts from a folder of PICTs. See develop issue 20,
- // Graphical Truffles column.
- //
-
-
- #include "MoreFilesExtras.h"
- #include "AppInterface.h" // for AppendStr31 proto in utils.c
-
- #define kNumFSSpecs 2
- #define kPICTHeaderSize 512 // the size of the header of a PICT file
-
- // Prototypes
- OSErr DoBatchClutStrip(void);
- OSErr StripPICTFile(FSSpec *pictFileSpec, FSSpec *targetDirSpec);
- OSErr SaveNewPict(PicHandle newPict, FSSpec *pictFileSpec,
- FSSpec *targetDirSpec);
-
- Boolean CustomGet(FSSpec *fSpec);
- pascal void StripClutProc(BitMap *src,
- Rect *srcR, Rect *dstR,
- short mode, RgnHandle msk);
-
- pascal OSErr GetTypedFilesInDir(short vRefNum,
- long dirID,
- StringPtr name,
- OSType fileType,
- FSSpecPtr items,
- short reqItemCount,
- short *actItemCount,
- short *itemIndex);
-
- // Globals
- CQDProcs stripClutProcs; // Set of QDProcs that includes our custom bitsProc
- Boolean gClutStripped; // Set by the bitsProc to indicate if the clut was removed
-
- extern WindowPtr gWindow; // The one and only window (gag)
-
- // Search recursively through all the files in a directory, strip the clut from
- // every PICT file that has one
- OSErr DoBatchClutStrip(void)
- {
- FSSpec dirSpec, newDirSpec, fileSpecs[kNumFSSpecs];
- Boolean goodSelection;
- short actItemCount, itemIndex;
- long newDirID, i;
- OSErr err;
-
- // Select directory
- goodSelection = CustomGet(&dirSpec);
- if(goodSelection == false) // User canceled
- {
- SysBeep(10);
- return noErr;
- }
-
- // Create new directory for modified PICTs
- newDirSpec = dirSpec;
- AppendStr31(newDirSpec.name, "\p.stripped");
- err = FSpDirCreate(&newDirSpec, smCurrentScript, &newDirID);
-
- // If the directory exists already, empty it
- if(err == dupFNErr)
- {
- err = DeleteDirectoryContents(newDirSpec.vRefNum, newDirSpec.parID, newDirSpec.name);
- }
-
- if(err != noErr)
- {
- SysBeep(10);
- return err;
- }
-
- // Initialize our bottlenecks to strip cluts
- SetStdCProcs(&stripClutProcs); // default procs
- stripClutProcs.bitsProc = NewQDBitsProc(StripClutProc);
-
- // Show the window
- ShowWindow(gWindow);
- SetPort(gWindow);
-
- // Process all PICTs in directory
- itemIndex = 1;
- while(true)
- {
- // Get all the PICT files in the directory, up to kNumFSSpecs
- GetTypedFilesInDir(dirSpec.vRefNum, dirSpec.parID, dirSpec.name, 'PICT',
- fileSpecs, kNumFSSpecs, &actItemCount, &itemIndex);
-
- // For each PICT
- for(i = 0; i < actItemCount; i++)
- {
- // Open PICT, strip clut, save new version
- err = StripPICTFile(&fileSpecs[i], &newDirSpec);
- if(err != noErr)
- {
- // Error, let's clean up and return
- DeleteDirectory(newDirSpec.vRefNum, newDirSpec.parID, newDirSpec.name);
- return err;
- }
- }
-
- if(actItemCount < kNumFSSpecs) // we're done
- break;
- }
-
- // Hide window again
- HideWindow(gWindow);
-
- // Beep
- SysBeep(10);
-
- return noErr;
- }
-
- OSErr StripPICTFile(FSSpec *pictFileSpec, FSSpec *targetDirSpec)
- {
- OSErr err = noErr;
- PicHandle oldPict, newPict;
- Rect pictRect;
- short refNum;
- long pictSize;
-
- // Open file
- err = FSpOpenDF(pictFileSpec, fsRdPerm, &refNum);
- if(err == noErr)
- {
- // Get the size of the data in the file
- err = GetEOF(refNum, &pictSize);
- if(err == noErr)
- {
- // subtract standard PICT header length
- pictSize -= kPICTHeaderSize;
-
- // Try to allocate a handle big enough, first in temp mem, then app mem
- oldPict = (PicHandle)TempNewHandle(pictSize, &err);
- if(oldPict == nil || err != noErr) // Try for app mem
- {
- oldPict = (PicHandle)NewHandle(pictSize);
- err = MemError();
- }
-
- // If it worked, read in the pict
- if(oldPict != nil)
- {
- HLock((Handle)oldPict);
-
- // Set position to just after the file header
- err = SetFPos(refNum, fsFromStart, (long)kPICTHeaderSize);
- if(err == noErr)
- {
- err = FSRead(refNum, &pictSize, *oldPict);
- if(err == noErr)
- {
- // We have the PICT as a handle. Now just draw it
- // into a new picture
- pictRect = (**oldPict).picFrame;
- ClipRect(&pictRect);
-
- // Install custom bottlenecks and draw it, stripping clut
- qd.thePort->grafProcs = (QDProcsPtr)(&stripClutProcs);
- newPict = OpenPicture(&pictRect);
- DrawPicture(oldPict, &pictRect);
- ClosePicture();
- qd.thePort->grafProcs = nil;
-
- // Check for errors: QDError() doesn't seem to work,
- // but I noticed picSize was -1 when it died on one picture.
- // So what the hell.
- if(QDError() != noErr || (*newPict)->picSize != -1)
- {
- // Check global to see if a clut was stripped
- if(gClutStripped)
- {
- // Draw new picture in window
- DrawPicture(newPict, &pictRect);
-
- // Save in a new file
- err = SaveNewPict(newPict, pictFileSpec, targetDirSpec);
- if(err != noErr)
- DebugStr("\pFailed in SaveNewPict, but keep going");
- }
- }
- KillPicture(newPict);
- }
- }
- DisposHandle((Handle)oldPict);
- oldPict = nil;
- }
- else
- DebugStr("\pOut of Memory!");
- }
- FSClose(refNum);
- }
- return err;
- }
-
-
- // Save the given picture into a new file, like the old one but in the target directory
- OSErr SaveNewPict(PicHandle newPict, FSSpec *pictFileSpec, FSSpec *targetDirSpec)
- {
- OSErr err;
- long dirID, writeSize;
- Boolean isDir;
- FSSpec newPictSpec;
- FInfo info;
- short refNum;
- Ptr zeros;
-
- // First get the actual dirID of the destination directory
- err = DirIDFromFSSpec(targetDirSpec, &dirID, &isDir);
- if(err == noErr && isDir)
- {
- // Now make an FSSpec for the new file
- err = FSMakeFSSpec(targetDirSpec->vRefNum, dirID, pictFileSpec->name,
- &newPictSpec);
-
- // Should get an fnfErr back, since the file doesn't exist. If not,
- // do nothing
- if(err == fnfErr)
- {
- // Get the FInfo for the old file so we can use the same type and creator
- err = FSpGetFInfo(pictFileSpec, &info);
- if(err == noErr)
- {
- // Make the new file
- err = FSpCreate(&newPictSpec, info.fdCreator, info.fdType,
- smCurrentScript);
- if(err == noErr)
- {
- // Open it
- err = FSpOpenDF(&newPictSpec, fsWrPerm, &refNum);
- if(err == noErr)
- {
- // Write out zeros for header bytes
- writeSize = kPICTHeaderSize;
- zeros = NewPtrClear(writeSize);
- if(zeros != nil)
- {
- err = FSWrite(refNum, &writeSize, zeros);
- DisposePtr(zeros);
- if(err == noErr)
- {
- // Write out the pict
- writeSize = GetHandleSize((Handle)newPict);
- HLock((Handle)newPict); // needed?
- err = FSWrite(refNum, &writeSize, *newPict);
- }
- }
- else err = memFullErr;
- FSClose(refNum);
- }
- }
- }
- }
- }
- return err;
- }
-
-
- // this is the custom bits proc that strips the color table
- pascal void StripClutProc(BitMap *src,
- Rect *srcR, Rect *dstR,
- short mode, RgnHandle msk)
- {
- CTabHandle saveCTH = nil;
-
- // Assume there's no clut to strip
- gClutStripped = false;
-
- // If it's a PixMap...
- if(src->rowBytes & 0x8000)
- {
- // ...and it's indexed...
- if(((PixMap *)src)->pixelSize < 16)
- {
- // ...save color table handle and...
- saveCTH = ((PixMapPtr) src)->pmTable;
- // ...replace it with nil instead.
- ((PixMapPtr) src)->pmTable = nil;
- // Tell the world what we've done
- gClutStripped = true;
- }
- }
-
- // Let QuickDraw do the work.
- StdBits(src, srcR, dstR, mode, msk);
-
- // Restore saved handle if necessary.
- if(saveCTH != nil)
- ((PixMapPtr) src)->pmTable = saveCTH;
- }
-
- // Modified version of GetDirItems from MoreFiles
- pascal OSErr GetTypedFilesInDir(
- short vRefNum,
- long dirID,
- StringPtr name,
- OSType fileType, // Only return files of this type
- FSSpecPtr items, // Array of FSSpecs to return items
- short reqItemCount, // Number of items in array
- short *actItemCount, // Actual number returned
- short *itemIndex) // start with 1, then use what's returned
- {
- CInfoPBRec pb;
- OSErr error = noErr;
- long theDirID;
- Boolean isDirectory;
- FSSpec *endItemsArray = items + reqItemCount;
-
- /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */
- /* to this routine, I could rip out calls to DetermineVRefNum and GetDirID and this */
- /* routine would be much faster because of the overhead of DetermineVRefNum and */
- /* GetDirID and because GetDirID blows away the directory index hint the Macintosh */
- /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */
- /* pass a big array of FSSpecs so you can get the directory's contents with few calls */
- /* to this routine. */
-
- /* get the real volume reference number */
- error = DetermineVRefNum(name, vRefNum, &pb.hFileInfo.ioVRefNum);
- if ( error != noErr )
- return ( error );
-
- /* and the real directory ID of this directory (and make sure it IS a directory) */
- error = GetDirID(vRefNum, dirID, name, &theDirID, &isDirectory);
- if ( error != noErr )
- return ( error );
- else if ( !isDirectory )
- return ( dirNFErr );
-
-
- *actItemCount = 0;
- for ( ; (items < endItemsArray) && (error == noErr); )
- {
- pb.hFileInfo.ioNamePtr = (StringPtr) &items->name;
- pb.hFileInfo.ioDirID = theDirID;
- pb.hFileInfo.ioFDirIndex = *itemIndex;
- error = PBGetCatInfoSync(&pb);
- if ( error == noErr )
- {
- items->parID = pb.hFileInfo.ioFlParID; /* return item's parID */
- items->vRefNum = pb.hFileInfo.ioVRefNum; /* return item's vRefNum */
- ++*itemIndex; /* prepare to get next item in directory */
-
- if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 )
- {
- if(pb.hFileInfo.ioFlFndrInfo.fdType == fileType)
- {
- ++*actItemCount; /* keep this item */
- ++items; /* point to next item */
- }
- }
- }
- }
- return ( error );
- }
-